/*******************************************************************************
 * Copyright (c) 2001 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal;

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.ui.IPerforceUIConstants;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.dialogs.ConfirmationDialog;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileModificationValidator;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.RepositoryProvider;

/**
  * @version $Revision: 187 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class PerforceFileModificationValidator 
	implements IFileModificationValidator
{
	// ------------------------------------------------------------------------- Public Constructors
	
	/** Constructor for PerforceFileModificationValidator. */
	public PerforceFileModificationValidator()
	{
	}
	
	// ------------------------------------------------------------------------------ Public Methods

	/** @see IFileModificationValidator#validateEdit(IFile[], Object) */
	public IStatus validateEdit(IFile[] files, Object context)
	{
		P4TeamProvider provider =
			(P4TeamProvider) RepositoryProvider.getProvider(files[0].getProject());

		try
		{
			files = filesToCheckout(files);
			if (files.length > 0)
			{
				if (!promptForCheckout(context, files))
				{
					return new Status(
						IStatus.ERROR, 
						PerforceCorePlugin.ID, 
						IStatus.ERROR, 
						"The user refused to open the file for edit.", 
						null);
				}

				provider.openForEdit(files, IResource.DEPTH_ZERO, new NullProgressMonitor());
			}
			
			return new Status(IStatus.OK, PerforceCorePlugin.ID, IStatus.OK, "", null);
		}
		catch (PerforceException e)
		{
			return e.getStatus();
		}
	}

	/** @see IFileModificationValidator#validateSave(IFile) */
	public IStatus validateSave(IFile file)
	{
		P4TeamProvider provider =
			(P4TeamProvider) RepositoryProvider.getProvider(file.getProject());

		IStatus result = new Status(IStatus.OK, PerforceCorePlugin.ID, IStatus.OK, "", null);
		if (provider.hasRemote(file))
		{
			try 
			{
				if (!provider.isCheckedOut(file))
				{
					provider.openForEdit(
						new IResource[] { file }, 
						IResource.DEPTH_ZERO, 
						new NullProgressMonitor());
				}
			} 
			catch (PerforceException e) 
			{
				result = e.getStatus();
			}
		}
		
		return result;
	}
	
	// ------------------------------------------------------------------------------ Private Method

	/** Returns an array of files that the need to be opened for edit (based on the given files)
	  *
	  * @param files the files.
	  * @return array of unopened files. 
	  */
	private IFile[] filesToCheckout(IFile[] files)
	{
		P4TeamProvider provider =
			(P4TeamProvider) RepositoryProvider.getProvider(files[0].getProject());
		
		List list = new ArrayList();
		for (int i = 0; i < files.length; i++)
		{
			if (provider.hasRemote(files[i]))
			{
				if (!provider.isCheckedOut(files[i]))
				{
					list.add(files[i]);
				}
			}
		}
		
		return (IFile[]) list.toArray(new IFile[0]);
	}

	/** Prompts the user for checkout of the given files.
	  *
	  * @param context the shell.
	  * @param files the files to open.
	  * @return true if files should be opened for edit. 
	  * 
	  * @throws PerforceException in case of an unexpected error. 
	  */
	private boolean promptForCheckout(Object context, final IFile[] files)
		throws PerforceException
	{
		IPreferenceStore store = PerforceUIPlugin.getPlugin().getPreferenceStore();
		if (store.getBoolean(IPerforceUIConstants.PREF_DONT_PROMPT_AUTOMATIC_OPEN))
		{
			return true;
		}
		else
		{
			final String message =
				"The system has indicated that one or more files not currently " +
				"opened for edit need to be changed. Do you want them to be " +
				"opened for edit?";

			final boolean[] pressedCancel = { true };			
			final Shell shell = 
				(context != null) ? (Shell) context : PerforceUIPlugin.getActiveShell(); 
			shell.getDisplay().syncExec(new Runnable()
			{
				public void run()
				{				
					pressedCancel[0] = 
						!ConfirmationDialog.openConfirmation(
							shell, 
							"Open for Edit", 
							message, 
							files);
				}
			});
			
			return !pressedCancel[0];
		}
	}
}
